package com.braska.grave.netty.worker;

import com.braska.grave.netty.codec.JSONDecoder;
import com.braska.grave.netty.codec.JSONEncoder;
import com.braska.grave.netty.handler.NettyServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author shenyuhang
 * @date 2020/3/30
 **/
public class ServerWorker extends ChannelInitializer {

    private static final Logger logger = Logger.getLogger(ServerWorker.class.getName());
    private String remoteAddress;
    private Map<String, Object> serviceMap;
    EventLoopGroup bossGroup;
    EventLoopGroup workerGroup;
    NettyServerHandler handler;

    public ServerWorker(String remoteAddress, Map<String, Object> serviceMap) {
        this.remoteAddress = remoteAddress;
        this.serviceMap = serviceMap;
        this.handler = new NettyServerHandler(this.serviceMap);
    }

    public void open() {
        try {
            int parallel = Runtime.getRuntime().availableProcessors() * 2;
            ServerBootstrap bootstrap = new ServerBootstrap();
            this.bossGroup = new NioEventLoopGroup();
            // todo 使用线程池，提高并发能力
            this.workerGroup = new NioEventLoopGroup(parallel);
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childHandler(this);
            String[] hostAndPort = this.remoteAddress.split(":");
            if (hostAndPort == null || hostAndPort.length != 2) {
                throw new RuntimeException("remoteAddress is error.");
            }
            ChannelFuture cf = bootstrap.bind(hostAndPort[0], Integer.parseInt(hostAndPort[1])).sync();
            // todo 信息写入注册中心
            // registry.register(serverAddress);
            logger.info("netty 服务器启动.监听端口:" + hostAndPort[1]);
            //等待服务端监听端口关闭
            cf.channel().closeFuture().sync();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "netty server open failed.", e);
            this.bossGroup.shutdownGracefully();
            this.workerGroup.shutdownGracefully();
        }
    }

    @Override
    protected void initChannel(Channel channel) throws Exception {
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast(new IdleStateHandler(0, 0, 60));
        pipeline.addLast(new JSONEncoder());
        pipeline.addLast(new JSONDecoder());
        pipeline.addLast(this.handler);
    }
}
